07. Updating UI - Code

L6 A07 Updating UI - Code

In this step, you’ll implement updating the UI based on the authentication state. When the user is logged in, you can personalize their home screen by displaying their name. You will also update the Login button to be a Logout button when the user is logged in.

  1. The first thing you need to do is provide a way for other classes in the app to know when a user has logged in or out. For this purpose, the FirebaseUserLiveData.kt class is already created for you. However, the class doesn’t do anything yet as the value of the LiveData isn’t being updated.

    Since you are using the FirebaseAuth library, you can listen to changes to the logged in user with the FirebaseUser. AuthStateListener callback that’s implemented for you as part of the FirebaseUI library. This callback will get triggered whenever a user logs in or out of your app.

    Notice that FirebaseUserLiveData.kt defines the authStateListener variable. You will use this variable to store the value of the LiveData. The authStateListener variable was created so that you can properly start and stop listening to changes in the auth state based on the state of your application. For example, if the user puts the app into the background, then the app should stop listening to auth state changes in order to prevent any potential memory leaks.

    Update authStateListener so that the value of your FirebaseUserLiveData corresponds to the current Firebase user.

FirebaseUserLiveData.kt

private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
   value = firebaseAuth.currentUser
}
  1. Next, in LoginViewModel.kt, create an authenticationState variable based off of the FirebaseUserLiveData object you just implemented. By creating this authenticationState variable, other classes can now query for whether the user is logged in or not through the LoginViewModel.

LoginViewModel.kt

val authenticationState = FirebaseUserLiveData().map { user ->
   if (user != null) {
       AuthenticationState.AUTHENTICATED
   } else {
       AuthenticationState.UNAUTHENTICATED
   }
}
  1. Now in MainFragment.kt’s observeAuthenticationState() you can use the authenticationState variable you just added in LoginViewModel and change the UI accordingly. If there is a logged-in user, authButton should display Logout.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }

                // TODO 2. If the user is logged in, 
                 // you can customize the welcome message they see by
                 // utilizing the getFactWithPersonalization() function provided

           }
           else -> {
               // TODO 3. Lastly, if there is no logged-in user, 
                // auth_button should display Login and
                //  launch the sign in screen when clicked.
           }
       }
   })
}
  1. If the user is logged in, you can customize the welcome message they see by utilizing the getFactWithPersonalization() function provided in MainFragment.

MainFragment.kt

binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
  1. Lastly, if there is no logged-in user (when authenticationState is anything other than LoginViewModel.AuthenticationState.AUTHENTICATED), auth_button should display “Login” and launch the sign in screen when clicked. There should also be no personalization of the message displayed.

MainFragment.kt

binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay
  1. With all the steps completed, your final observeAuthenticationState() method should look similar to the example shown below.

MainFragment.kt

private fun observeAuthenticationState() {
   val factToDisplay = viewModel.getFactToDisplay(requireContext())

   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
        // TODO 1. Use the authenticationState variable you just added 
         // in LoginViewModel and change the UI accordingly.
       when (authenticationState) {
            // TODO 2.  If the user is logged in, 
             // you can customize the welcome message they see by
             // utilizing the getFactWithPersonalization() function provided
           LoginViewModel.AuthenticationState.AUTHENTICATED -> {
               binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
               binding.authButton.text = getString(R.string.logout_button_text)
               binding.authButton.setOnClickListener {
                   // TODO implement logging out user in next step
               }
           }
           else -> {
                // TODO 3. Lastly, if there is no logged-in user, 
                 // auth_button should display Login and
                 // launch the sign in screen when clicked.
               binding.welcomeText.text = factToDisplay

               binding.authButton.text = getString(R.string.login_button_text)
               binding.authButton.setOnClickListener {
                   launchSignInFlow()
               }
           }
       }
   })
}
  1. Now the UI should update according to whether a user is logged in or not. Run the app again. If everything is working properly, the home screen should now greet you by your name in addition to displaying an Android fact. The Login button should also now display Logout.
  2. Since the app allows users to login, it should also provide them with a way to logout. Here’s an example of how to log out a user with just one line of code:
AuthUI.getInstance().signOut(requireContext())

In MainFragment.kt’s observeAuthenticationState(), add the logout logic so that the auth_button functions correctly when there is a logged in user.